﻿using System;
using System.Net.Sockets;
using Jiubang.Communication.Common;
using Jiubang.Communication.Server.Common;
using Jiubang.Communication.Server.SessionControl;

namespace Jiubang.Communication.Server.RequestRouter {
    /// <summary>
    ///   请求上下文
    /// </summary>
    public struct RequestContext {
        private readonly SocketAsyncEventArgs _socketAsyncEventArgs;
        private readonly IMessageSender _messageSender;

        internal RequestContext(SocketAsyncEventArgs socketAsyncEventArgs, IMessageSender messageSender) {
            _socketAsyncEventArgs = socketAsyncEventArgs;
            _messageSender = messageSender;
            socketAsyncEventArgs.SetBuffer(socketAsyncEventArgs.Offset + 1, socketAsyncEventArgs.Count - 1);
        }

        /// <summary>
        ///   获取命令位标识
        /// </summary>
        public byte ActionCode {
            get { return _socketAsyncEventArgs.Buffer[_socketAsyncEventArgs.Offset - 1]; }
        }

        /// <summary>
        /// 获取请求消息正文的反序列后生成的对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="converter"></param>
        /// <returns></returns>
        public T GetValue<T>(IBytesConverter<T> converter) {
            if (converter == null)
                throw new ArgumentNullException("converter");
            return converter.Deserialize(_socketAsyncEventArgs.Buffer, _socketAsyncEventArgs.Offset);
        }

        /// <summary>
        /// 向客户端回复消息。
        /// 如客户端等待当前请求序号的回复，
        /// 则必须使用该方法触发客户端的完成事件。
        /// 否则客户端将等待直到超时。
        /// </summary>
        /// <param name="value"></param>
        /// <param name="converter"></param>
        public void Response<T>(T value, IBytesConverter<T> converter) {
            if (converter == null)
                throw new ArgumentNullException("converter");

            _messageSender.SendAsync(_socketAsyncEventArgs.AcceptSocket,
                                   converter.Serialize(value, _socketAsyncEventArgs.Offset - 2));
        }

        /// <summary>
        /// 向多个客户端广播内容。
        /// 如构造函数传入的IResponsable对象未实现IBroadcastable接口时将抛出异常。
        /// </summary>
        /// <param name="value"></param>
        /// <param name="converter"></param>
        /// <param name="option"></param>
        public void Broadcast<T>(T value, IBytesConverter<T> converter, BroadcastOption option) {
            if (converter == null)
                throw new ArgumentNullException("converter");

            var broadcastable = _messageSender as IBroadcastable;
            if (broadcastable == null) {
                throw new NotSupportedException(string.Format("类型{0}不实现IBroadcastable接口",_messageSender.GetType()));
            }

            broadcastable.Broadcast(_socketAsyncEventArgs.AcceptSocket,
                                    converter.Serialize(value, _socketAsyncEventArgs.Offset - 2), option);
        }
    }
}